﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "DataConvertor.h"
#include <QMessageBox>
#include <QFileInfo>
#include <QDir>
#include <QTextCodec>
#include <QBitArray>
#include "BurnToolCommon/StdAfx.h"
#include "DataConvertor.h"
#include "SecureLink/Channel.h"
#include "BurnToolCommon/Global.h"
#include "BurnToolCommon/UKeyUtils.h"
#include "BurnToolCommon/AESUtils.h"
#include "../platform/Securec/securec.h"
MyStringClass::StringClass DataConvertor::stringClass;
namespace {
    const int NUM_TWO = 2;
    const int NUM_THREE = 3;
    const int NUM_TEN = 10;
    const int FLOWCTRL_VAL_TWO = 2;
    const int FLOWCTRL_VAL_THREE = 3;
    const int BASE_CHANGE_HEX = 16;
    const int BYTE_LEN = 8;
}

DataConvertor::DataConvertor()
{
}

DataConvertor::~DataConvertor()
{
}

QString DataConvertor::ParityChar2QString(QSerialPort::Parity parity)
{
    QString strParity = QObject::tr("None");
    if (parity == QSerialPort::OddParity) {
        strParity = QObject::tr("Odd");
    } else if (parity == QSerialPort::EvenParity) {
        strParity = QObject::tr("Even");
    } else if (parity == QSerialPort::NoParity) {
        strParity = QObject::tr("None");
    }
    return strParity;
}

QSerialPort::Parity DataConvertor::ParityQString2Char(QString strParity)
{
    QSerialPort::Parity parity = QSerialPort::NoParity;
    if (strParity == QObject::tr("Odd")) {
        parity = QSerialPort::OddParity;
    } else if (strParity == QObject::tr("Even")) {
        parity = QSerialPort::EvenParity;
    } else if (strParity == QObject::tr("None")) {
        parity = QSerialPort::NoParity;
    }
    return parity;
}


QString DataConvertor::FlowctrlInt2QString(int flowctrl)
{
    QString strFlowctrl = QObject::tr("None");
    if (flowctrl == 1) {
        strFlowctrl = QObject::tr("Hardware");
    } else if (flowctrl == 0) {
        strFlowctrl = QObject::tr("None");
    } else if (flowctrl == FLOWCTRL_VAL_TWO) {
        strFlowctrl = QObject::tr("Onlyrts");
    } else if (flowctrl == FLOWCTRL_VAL_THREE) {
        strFlowctrl = QObject::tr("Onlycts");
    }
    return strFlowctrl;
}

int DataConvertor::FlowctrlQString2Int(QString strFlowctrl)
{
    int flowctrl = 0;
    if (strFlowctrl == QObject::tr("Hardware")) {
        flowctrl = 1;
    } else if (strFlowctrl == QObject::tr("None")) {
        flowctrl = 0;
    } else if (strFlowctrl == QObject::tr("Onlyrts")) {
        flowctrl = 2; // rts 2
    } else if (strFlowctrl == QObject::tr("Onlycts")) {
        flowctrl = 3; // rts 3
    }
    return flowctrl;
}

U32 DataConvertor::Str2U32DecHex(const QString &str)
{
    QString mStrPrefix = str.left(2);

    int nBase = 0;
    if (mStrPrefix.compare(IDS_STRING_33091) == 0) { // Hex
        nBase = 16; // 若以0x开头为16进制
    } else {
        nBase = 10; // 若没有0x则为10进制
    }
    bool ok;
    U32 ulRet = str.toUInt(&ok, nBase);
    return ulRet;
}

void DataConvertor::RefreshComList(QStringList &result)
{
    result.clear();
    HKEY hKey = nullptr;
    int ret = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, IDS_STRING_33109.toStdWString().c_str(), 0,
        KEY_READ, &hKey);
    if (ret == ERROR_SUCCESS) {
        int i = 0;
        TCHAR portName[256]; // 256 name max len
        TCHAR commName[256]; // 256 name max len
        DWORD dwLong;
        DWORD dwSize;
        while (i < INT_MAX) {
            dwLong = dwSize = sizeof(portName);
            if (::RegEnumValue(hKey, i, portName, &dwLong, nullptr, nullptr,
                reinterpret_cast<PUCHAR>(commName), &dwSize) == ERROR_NO_MORE_ITEMS) {
                break;
            }
            QString strtmp = QString::fromWCharArray(commName);
            result.push_back(strtmp);
            i++;
        }
        RegCloseKey(hKey);
    }
    std::vector<int> tmp;
    for (int i = 0; i < result.size(); i++) {
        int com = result[i].mid(3).toInt();
        tmp.push_back(com);
    }
    sort(tmp.begin(), tmp.end());
    result.clear();
    for (unsigned long long i = 0; i < tmp.size(); i++) {
        QString com;
        com = QString("COM%1").arg(tmp[i]);
        result.push_back(com);
    }
}

QStringList DataConvertor::GetValidBaud()
{
    QStringList result;
    result.clear();
    result<< "6000000" << "5000000"<< "4000000" << "3000000" << "2000000" << "1500000" << "1000000" << "921600"
        << "750000" << "600000"  << "512000" << "500000" << "460800" << "115200"
        << "57600" << "56000" << "43000" << "38400" << "19200" << "9600" << "4800";
    return result;
}


QStringList DataConvertor::GetValidPackageSize()
{
    QStringList result;
    result.clear();
    result << "8192" << "4096" << "2048" << "1024";
    return result;
}

QStringList DataConvertor::GetValidPackageSize3X()
{
    QStringList result;
    result.clear();
    result << "4096" << "20480";
    return result;
}

QStringList DataConvertor::GetValidDatabit()
{
    QStringList result;
    result.clear();
    result << "8";
    return result;
}

QStringList DataConvertor::GetValidStopbit()
{
    QStringList result;
    result.clear();
    result << "1" << "2";
    return result;
}

QStringList DataConvertor::GetValidParity()
{
    QStringList result;
    result.clear();
    result << QObject::tr("Odd") << QObject::tr("Even") << QObject::tr("None");
    return result;
}

QStringList DataConvertor::GetValidFlowctrl()
{
    QStringList result;
    result.clear();
    result << QObject::tr("None") << QObject::tr("Hardware") << QObject::tr("OnlyRts") << QObject::tr("OnlyCts");
    return result;
}

QString DataConvertor::GetAppPath()
{
    TCHAR szInstallPath[MAX_PATH] = { 0 };
    GetModuleFileName(nullptr, szInstallPath, MAX_PATH);
    S32 i = 0;
    S32 j = 0;
    while (szInstallPath[i] != 0) {
        if (szInstallPath[i] == _T('\\')) {
            j = i;
        }
        i++;
    }
    szInstallPath[j] = _T('\0');
    QString installPath = QString::fromWCharArray(szInstallPath);
    return installPath;
}

QString DataConvertor::GetBurnToolConfigPathNew()
{
    return GetAppPath() + "\\BurnTool_config.ini";
}

void DataConvertor::AnalysMultifBin(QString strPath, BIN_INFO_ARRAY &infoArray, QString &version,
                                    bool &isEncrypt, ENCRYPT_BUFFER &buffer)
{
    QString cleanPath = QDir::cleanPath(strPath);
    if (cleanPath.isEmpty()) {
        return;
    }
    QFile binFile(cleanPath);
    if (binFile.open(QIODevice::ReadOnly) == 0) {
        return;
    }
    qint64 fileLen = reinterpret_cast<qint64>(binFile.size());
    if (fileLen > 0xffffffff) {
        return;
    }
    binFile.close();
    if (!AnalysMultifBinSub(strPath, infoArray, version, binFile, fileLen,
        isEncrypt, buffer)) {
        return;
    }

    int loaderNumber = 0;
    for (int i = 0; i < infoArray.GetSize(); i++) {
        if (infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            loaderNumber++;
        }
    }
    if (loaderNumber > 2) { // loader num max 2
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33107());
        return;
    }
}

bool DataConvertor::AnalysMultifBinSub(QString strPath, BIN_INFO_ARRAY &infoArray, QString &version,
                                       QFile &binFile, const qint64 &fileLen, bool &isEncrypt,
                                       ENCRYPT_BUFFER &buffer)
{
    if (fileLen > 0xffffffff) {
        return false;
    }
    isEncrypt = false;
    CHAR *pBurnFile = new char[fileLen]();
    if (pBurnFile == nullptr) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33092());
        return false;
    }
    SecureZeroMemory(pBurnFile, fileLen);
    UINT len = sizeof(FWPKG_HEAD);
    if (binFile.open(QIODevice::ReadOnly) == 0) {
        delete[] pBurnFile;
        pBurnFile = nullptr;
        return false;
    }
    binFile.read(pBurnFile, len);
    binFile.close();
    auto *fwpkgHead = reinterpret_cast<FWPKG_HEAD *>(pBurnFile);
    if (binFile.open(QIODevice::ReadOnly) == 0) {
        delete[] pBurnFile;
        pBurnFile = nullptr;
        return false;
    }
    if (fwpkgHead->flag == 0xefbeaddf && fwpkgHead->imageNum < 0xffff) {
        UINT lenImageInfo = sizeof(IMAGE_INFO) * fwpkgHead->imageNum;
        SecureZeroMemory(pBurnFile, fileLen);
        binFile.read(pBurnFile, len + lenImageInfo);
        fwpkgHead = reinterpret_cast<FWPKG_HEAD *>(pBurnFile);
    } else if ((fwpkgHead->flag >= 0xefbeadd0 && fwpkgHead->flag < 0xefbeaddf) && fwpkgHead->imageNum < 0xffff) {
        len = sizeof(IMAGE_INFO_NEW);
        UINT lenImageInfo = sizeof(IMAGE_INFO_NEW) * fwpkgHead->imageNum;
        SecureZeroMemory(pBurnFile, fileLen);
        binFile.read(pBurnFile, len + lenImageInfo);
    }
    binFile.close();
    if (fwpkgHead->flag == 0xefbeaddf && fwpkgHead->imageNum < 0xffff) {
        ParseNormalFwpkg(fwpkgHead, fileLen, strPath, infoArray);
    } else if ((fwpkgHead->flag >= 0xefbeadd0 && fwpkgHead->flag < 0xefbeaddf) &&
        fwpkgHead->imageNum < 0xffff) {
        ParseNewFwpkg(pBurnFile, fileLen, version, strPath, infoArray);
    } else {
        bool retValue = DecryptAESKeyAndWriteFile(strPath, infoArray, version, buffer);
        if (retValue) {
            isEncrypt = true;
        } else {
            AnalysMultifBinSubAdd(strPath, fileLen, infoArray);
        }
    }
    if (pBurnFile != nullptr) {
        delete[] pBurnFile;
        pBurnFile = nullptr;
    }
    return true;
}

void DataConvertor::AnalysMultifBinSubAdd(const QString &strPath, const qint64 &fileLen, BIN_INFO_ARRAY &infoArray)
{
    BIN_INFO info;
    info.path = strPath;
    info.burnAddr = QString::number(0);
    info.fileIndex = QString::number(0);
    info.fileSize = QString::number(fileLen);
    info.burnSize = "0x200000";
    infoArray.Add(info);
}

void DataConvertor::ParseNormalFwpkg(FWPKG_HEAD *fwpkgHead,
    const U32 &fileLen, const QString &strPath, BIN_INFO_ARRAY &infoArray)
{
    if (fwpkgHead->imageNum > 0xff) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33093());
        return;
    }

    U32 crcDataLen = sizeof(FWPKG_HEAD) - 6 + sizeof(IMAGE_INFO) * fwpkgHead->imageNum; // 6 bytesnot include
    if (crcDataLen > fileLen) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33093());
        return;
    }
    if (fwpkgHead->crc != ChannelClass::Channel::SopCrc16(reinterpret_cast<U8 *>(&fwpkgHead->imageNum), crcDataLen)) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33094());
        return;
    }
    ParseFwpkgInfo(strPath, infoArray, fwpkgHead, true);
}

void DataConvertor::ParseFwpkgInfo(const QString &strPath, BIN_INFO_ARRAY &infoArray,
    FWPKG_HEAD *fwpkgHead, bool isShowInUi)
{
    for (int i = 0; i < fwpkgHead->imageNum; i++) {
        BIN_INFO info;
        info.type = fwpkgHead->info[i].type;
        if (isShowInUi && info.type == IMAGE_TYPE::IMAGE_TYPE_DATABASE) {
            continue;
        }
        info.path = strPath;
        fwpkgHead->info[i].name[31] = 0; // index 31
        info.fileName = QString::fromLocal8Bit(reinterpret_cast<CHAR *>(fwpkgHead->info[i].name));
        info.fileIndex = "0x" + QString::number(fwpkgHead->info[i].startIndex, BASE_CHANGE_HEX);
        info.fileSize = "0x" + QString::number(fwpkgHead->info[i].imageSize, BASE_CHANGE_HEX);
        info.burnAddr = "0x" + QString::number(fwpkgHead->info[i].burnAddr, BASE_CHANGE_HEX);
        info.burnSize = "0x" + QString::number(fwpkgHead->info[i].burnSize, BASE_CHANGE_HEX);
        if (isShowInUi && info.type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            infoArray.InsertAt(0, info);
        } else {
            infoArray.Add(info);
        }
    }
}

void DataConvertor::ParseNewFwpkg(CHAR *pBurnFile, const U32 &fileLen,
                                  QString &version, const QString &strPath, BIN_INFO_ARRAY &infoArray)
{
    auto *fwpkgHead = reinterpret_cast<FWPKG_HEAD_NEW *>(pBurnFile);
    if (fwpkgHead->imageNum > 0xff) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33093());
        return;
    }
    U32 crcDataLen =
        sizeof(FWPKG_HEAD_NEW) - 6 + sizeof(IMAGE_INFO_NEW) * fwpkgHead->imageNum; // 6 bytesnot include
    if (crcDataLen > fileLen) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33093());
        return;
    }
    if (fwpkgHead->crc != ChannelClass::Channel::SopCrc16(reinterpret_cast<U8 *>(&fwpkgHead->imageNum), crcDataLen)) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33094());
        return;
    }
    version = QString::fromLocal8Bit(reinterpret_cast<CHAR*>(fwpkgHead->name));
    ParseNewFwpkgInfo(strPath, infoArray, fwpkgHead, true);
}

void DataConvertor::ParseNewFwpkgInfo(const QString &strPath, BIN_INFO_ARRAY &infoArray,
    FWPKG_HEAD_NEW *fwpkgHead, bool isShowInUi)
{
    for (int i = 0; i < fwpkgHead->imageNum; i++) {
        BIN_INFO infoNew;
        infoNew.type = fwpkgHead->info[i].type;
        if (isShowInUi && infoNew.type == IMAGE_TYPE::IMAGE_TYPE_DATABASE) {
            continue;
        }
        infoNew.path = strPath;
        fwpkgHead->info[i].name[259] = 0; // index 259
        infoNew.fileName = QString::fromUtf8(reinterpret_cast<CHAR*>(fwpkgHead->info[i].name));
        infoNew.fileIndex = "0x" + QString::number(fwpkgHead->info[i].startIndex, BASE_CHANGE_HEX);
        infoNew.fileSize = "0x" + QString::number(fwpkgHead->info[i].imageSize, BASE_CHANGE_HEX);
        infoNew.burnAddr = "0x" + QString::number(fwpkgHead->info[i].burnAddr, BASE_CHANGE_HEX);
        infoNew.burnSize = "0x" + QString::number(fwpkgHead->info[i].burnSize, BASE_CHANGE_HEX);
        if (isShowInUi && infoNew.type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            infoArray.InsertAt(0, infoNew);
        } else {
            infoArray.Add(infoNew);
        }
    }
}

U32 DataConvertor::ByteStr2Buf(const QString &strByte0, PBYTE pucBuf, U32 &pulLen)
{
    QString strByte = strByte0;
    DeleteSpace(strByte);

    int n = strByte.length();
    if (n <= 0 || n - 2 > 0x10000 || pucBuf == nullptr) { // offset 2
        return ERR_SOP_FAILURE;
    }

    BOOL bEven = FALSE;
    if (n % NUM_TWO == 0) {
        pulLen = n / NUM_TWO;
        bEven = TRUE;
    } else {
        pulLen = n / NUM_TWO + 1;
        bEven = FALSE;
    }

    if (pulLen > NDM_UTIL_BUF_SIZE_MAX) {
        return ERR_SOP_FAILURE;
    }

    int iBuf;
    int i;
    QChar ch;
    if (bEven) {
        i = 0;
        iBuf = 0;
    } else {
        ch = strByte[0];
        pucBuf[0] = DbChar2Figure(0, ch);
        i = 1;
        iBuf = 1;
    }
    for (; i <= n - NUM_TWO; i = i + NUM_TWO) {
        QChar cHig = strByte[i];
        QChar cLow = strByte[i + 1];
        if (!IsFigureChar(cHig)) {
            return ERR_SOP_FAILURE;
        }
        if (!IsFigureChar(cLow)) {
            return ERR_SOP_FAILURE;
        }
        BYTE figure = DbChar2Figure(cHig, cLow);

        pucBuf[iBuf] = figure;
        iBuf++;
    }
    return ERR_SOP_SUCCESS;
}

bool DataConvertor::IsFigureChar(QChar ch)
{
    return IsDecNumChar(ch) || IsHexNumChar(ch);
}

BYTE DataConvertor::DbChar2Figure(QChar cHig, QChar cLow)
{
    BYTE byteHigh = Char2Figure(cHig);
    BYTE byteLow = Char2Figure(cLow);
    return BYTE((byteHigh << 0x04) + byteLow);
}

BYTE DataConvertor::Char2Figure(QChar ch)
{
    if (ch >= _T('0') && ch <= _T('9')) {
        return BYTE(ch.toLatin1() - '0');
    }
    if (ch >= _T('A') && ch <= _T('F')) {
        return BYTE(ch.toLatin1() - 'A' + NUM_TEN);
    }
    if (ch >= _T('a') && ch <= _T('f')) {
        return BYTE(ch.toLatin1() - 'a' + NUM_TEN);
    }
    return 0;
}

void DataConvertor::DeleteSpace(QString &str)
{
    int n = str.length();
    int iNew = 0;
    if (n == 0 || n - 1 > 0x0fffffff) {
        return;
    }
    for (int i = 0; i <= n - 1; i++) {
        QChar ch = str[i];
        if (ch != _T(' ')) {
            str.replace(iNew, 1, ch);
            iNew++;
        }
    }
    str = str.left(iNew);
}

bool DataConvertor::IsDecNumChar(QChar ch)
{
    if (ch == _T('0')) {
        return TRUE;
    } else if (ch == _T('1')) {
        return TRUE;
    } else if (ch == _T('2')) {
        return TRUE;
    } else if (ch == _T('3')) {
        return TRUE;
    } else if (ch == _T('4')) {
        return TRUE;
    } else if (ch == _T('5')) {
        return TRUE;
    } else if (ch == _T('6')) {
        return TRUE;
    } else if (ch == _T('7')) {
        return TRUE;
    } else if (ch == _T('8')) {
        return TRUE;
    } else if (ch == _T('9')) {
        return TRUE;
    } else {
        return false;
    }
}

bool DataConvertor::IsHexNumChar(QChar ch)
{
    if (IsDecNumChar(ch)) {
        return true;
    } else if (ch == _T('A')) {
        return true;
    } else if (ch == _T('B')) {
        return true;
    } else if (ch == _T('C')) {
        return true;
    } else if (ch == _T('D')) {
        return true;
    } else if (ch == _T('E')) {
        return true;
    } else if (ch == _T('F')) {
        return true;
    } else if (ch == _T('a')) {
        return true;
    } else if (ch == _T('b')) {
        return true;
    } else if (ch == _T('c')) {
        return true;
    } else if (ch == _T('d')) {
        return TRUE;
    } else if (ch == _T('e')) {
        return true;
    } else if (ch == _T('f')) {
        return true;
    } else {
        return false;
    }
}

bool DataConvertor::CheckLoader(BIN_INFO info, int ackFlag)
{
    QString cleanPath = QDir::cleanPath(info.path);
    if (cleanPath.isEmpty()) {
        return false;
    }
    QFile binFile(cleanPath);
    if (info.type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
        if (!binFile.open(QIODevice::ReadOnly)) {
            return false;
        }

        binFile.seek(info.GetFileIndex());
        char buffer[sizeof(BootHeader)];
        UINT nBytesRead = binFile.read(buffer, sizeof(BootHeader));
        if (nBytesRead != sizeof(BootHeader)) {
            binFile.close();
            return false;
        }

        auto *bootHead = reinterpret_cast<BootHeader*>(buffer);
        if (bootHead->subKeyOffset != 0) {
            binFile.seek(info.GetFileIndex() + bootHead->subKeyOffset);
            char buffer2[sizeof(SubKey)];
            UINT nBytesRead2 = binFile.read(buffer2, sizeof(SubKey));
            if (nBytesRead2 != sizeof(SubKey)) {
                binFile.close();
                return false;
            }
            auto *bootHead2 = reinterpret_cast<SubKey*>(buffer2);
            if (bootHead2->encryotFlag == ackFlag) {
                binFile.close();
                return true;
            } else {
                binFile.close();
                return false;
            }
        } else if (bootHead->subKeyOffset == 0 && ackFlag == 0x42) {
            binFile.close();
            return true;
        } else if (bootHead->subKeyOffset == 0 && ackFlag == 0) {
            binFile.close();
            return true;
        } else {
            binFile.close();
            return false;
        }
    }
    binFile.close();
    return false;
}

bool DataConvertor::AllPathFileExists(std::vector<QString> &path, std::vector<QString> &result)
{
    bool ret = true;
    for (auto item : path) {
        QFile file(item);
        if (!file.exists()) {
            result.push_back(item);
            ret = false;
        }
    }
    return ret;
}


bool DataConvertor::IsVisibleAscii(U8 item)
{
    if (item == 8 || item == 9 || item == 10 || item == 13) { // 8,9,10,13 is visible ascii
        return true;
    } else if (item >= 0x20 && item <= 0x7f) {
        return true;
    }
    return false;
}


U32 DataConvertor::Buf2ByteStr(const BYTE * const pucBuf, U32 ulLen, QString &strByte)
{
    if (pucBuf == nullptr) {
        return ERR_SOP_FAILURE;
    }
    if (ulLen <= 0 || ulLen > UINT_MAX / 2) { // 长度最大值是uint最大值的1/2
        return ERR_SOP_FAILURE;
    }
    int iStr = 0;
    int ulLenStr = static_cast<int>(ulLen * 0x02 + ulLen - 1);

    for (int i = 0; i < static_cast<int>(ulLen); i++) {
        TCHAR cLow = TCHAR(0);
        TCHAR cHig = TCHAR(0);
        BYTE byteTemp = pucBuf[i];
        Figure2DbChar(byteTemp, cHig, cLow);
        strByte += cHig;
        strByte += cLow;
        if (iStr + NUM_TWO <= ulLenStr - 1) {
            strByte += ' ';
        }
        iStr += NUM_THREE;
    }
    return ERR_SOP_SUCCESS;
}

U32 DataConvertor::Figure2DbChar(BYTE fig, TCHAR &cHig, TCHAR &cLow)
{
    BYTE figlow = BYTE(fig & 0x0f);
    BYTE figHig = BYTE((fig >> 0x04) & 0x0f);

    cHig = Figure2Char(figHig);
    cLow = Figure2Char(figlow);

    return ERR_SOP_SUCCESS;
}

TCHAR DataConvertor::Figure2Char(BYTE fig)
{
    if (fig <= 0x09) {
        return TCHAR(fig + _T('0'));
    } else if (fig >= 0x0a && fig <= 0x0f) {
        return TCHAR(fig - 0x0a + _T('A'));
    }
    return 0;
}

bool DataConvertor::FindChar(const unsigned char *data, unsigned int dataLen, char ch)
{
    if (data == nullptr || dataLen > 0xfffffff) {
        return false;
    }
    for (unsigned int i = 0; i < dataLen; i++) {
        if (data[i] == ch) {
            return true;
        }
    }
    return false;
}

U32 DataConvertor::Str2U32(QString str, int base)
{
    bool ok = false;
    U32 ulRet = str.toUInt(&ok, base);
    return ulRet;
}

bool DataConvertor::DecryptAESKeyAndWriteFile(const QString &in, BIN_INFO_ARRAY &infoArray,
                                              QString &version, ENCRYPT_BUFFER &buffer)
{
    BYTE* key = nullptr;
    DWORD keyLen = 0;
    QFileInfo fileInfo(in);
    QString filePath = fileInfo.path();
    QDir rootDir(filePath);
    QFileInfoList fileList = rootDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
    QString keyPath = "";
    for (QFileInfo info : fileList) {
        if (info.completeSuffix().contains("produce.ciphertext")) {
            keyPath = info.filePath();
            break;
        }
    }
    if (!QFile(keyPath).exists()) {
        return false;
    }
    Global::ReadFileData(keyPath, key, keyLen);
    if (key == nullptr) {
        return false;
    }
    key[256] = '\0'; // 取数据的前256字节
    keyLen = 256; // 取数据长度为256
    UKeyUtilsClass::UKeyUtils uKey;
    Global::EndianSwap(key, keyLen);
    uKey.DecryptAESKey(key, keyLen);
    bool ret = DecryptAndWriteFile(key, in, infoArray, version, buffer);
    int retSet = memset_s(key, keyLen, 0, keyLen);
    if (retSet != 0) {
        qDebug() << "memset error";
    }
    if (key != nullptr) {
        delete []key;
        key = nullptr;
    }
    return ret;
}

bool DataConvertor::DecryptAndWriteFile(BYTE *keyFile, const QString &dataFile, BIN_INFO_ARRAY &infoArray,
                                        QString &version, ENCRYPT_BUFFER &buffer)
{
    BYTE* data = nullptr;
    Global::ReadFileData(dataFile, data, buffer.bufferLen);
    if (data == nullptr) {
        return false;
    }
    AESUtilsClass::AESUtils aes;
    if (buffer.bufferLen <= 0) {
        printf("Memory is not compliant");
    }
    buffer.bufferData = new BYTE[buffer.bufferLen]();
    if (buffer.bufferData == nullptr) {
        delete []data;
        data = nullptr;
        return false;
    }
    aes.DecryptTLVData(keyFile, data, buffer.bufferLen, buffer.bufferData);
    delete []data;
    data = nullptr;
    if (buffer.bufferLen == 0 || buffer.bufferData == nullptr) {
        return false;
    }
    auto *fwpkgHead = reinterpret_cast<FWPKG_HEAD *>(buffer.bufferData);
    if (fwpkgHead->flag == 0xefbeaddf && fwpkgHead->imageNum < 0xffff) {
        ParseNormalFwpkg(fwpkgHead, buffer.bufferLen, dataFile, infoArray);
    } else if ((fwpkgHead->flag >= 0xefbeadd0 && fwpkgHead->flag < 0xefbeaddf) &&
        fwpkgHead->imageNum < 0xffff) {
        ParseNewFwpkg(reinterpret_cast<char*>(buffer.bufferData), buffer.bufferLen, version, dataFile, infoArray);
    } else {
        if (buffer.bufferData != nullptr) {
            delete []buffer.bufferData;
            buffer.bufferData = nullptr;
            buffer.bufferLen = 0;
        }
        return false;
    }
    return true;
}

void DataConvertor::AnalysMultifBin(QString strPath, BIN_INFO_ARRAY &infoArray, QString &version,
                                    ENCRYPT_BUFFER buffer)
{
    auto *fwpkgHead = reinterpret_cast<FWPKG_HEAD *>(buffer.bufferData);
    if (fwpkgHead->flag == 0xefbeaddf && fwpkgHead->imageNum < 0xffff) {
        ParseNormalFwpkg(fwpkgHead, buffer.bufferLen, strPath, infoArray);
    } else if ((fwpkgHead->flag >= 0xefbeadd0 && fwpkgHead->flag < 0xefbeaddf) &&
        fwpkgHead->imageNum < 0xffff) {
        ParseNewFwpkg(reinterpret_cast<CHAR*>(buffer.bufferData), buffer.bufferLen, version, strPath, infoArray);
    } else {
        AnalysMultifBinSubAdd(strPath, buffer.bufferLen, infoArray);
    }

    int loaderNum = 0;
    for (int i = 0; i < infoArray.GetSize(); i++) {
        if (infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            loaderNum++;
        }
    }
    if (loaderNum > 2) { // loader num max 2
        QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString33107());
        return;
    }
}

QByteArray DataConvertor::CodeGB2312(QString &fileName, const QString &coded)
{
    QTextCodec *code = QTextCodec::codecForName(coded.toLatin1().data());
    return code->fromUnicode(fileName).data();
}

QByteArray DataConvertor::Bits2Bytes(const QBitArray &bits)
{
    QByteArray bytes;
    bytes.resize(bits.count() / BYTE_LEN + ((static_cast<bool>(bits.count() / BYTE_LEN)) ? 0 : 1));
    bytes.fill(0);
    for (int i = 0; i < bits.count(); ++i) {
        bytes[i / BYTE_LEN] = (static_cast<unsigned char>(bytes.at(i / BYTE_LEN)) |
            ((bits[i] ? 1 : 0) << (i % BYTE_LEN)));
    }
    return bytes;
}

void DataConvertor::SetFileIndex(QMap<int, BIN_INFO> &actualMapBinFileInfo, bool isNewFwpkgMode)
{
    FWPKG_HEAD *fwpkgHead;
    FWPKG_HEAD_NEW *fwpkgHeadNew;
    int startFileIndex = 0;
    int startCommonLen = sizeof(fwpkgHead->flag) + sizeof(fwpkgHead->crc) + sizeof(fwpkgHead->imageNum)
            + sizeof(fwpkgHead->totalFileSize);
    if (isNewFwpkgMode) {
        startFileIndex = startCommonLen + sizeof(fwpkgHeadNew->name)
            + sizeof(IMAGE_INFO_NEW) * actualMapBinFileInfo.size();
    } else {
        startFileIndex = startCommonLen + sizeof(IMAGE_INFO) * actualMapBinFileInfo.size();
    }
    if (actualMapBinFileInfo.size() > 0) {
        actualMapBinFileInfo[0].fileIndex = QString::number(startFileIndex);
        for (int i = 1; i < actualMapBinFileInfo.size(); i++) {
            actualMapBinFileInfo[i].fileIndex =
                QString::number(Str2U32DecHex(actualMapBinFileInfo[i - 1].fileIndex)
                + Str2U32DecHex(actualMapBinFileInfo[i - 1].fileSize) + INTERVAL_EACH_FILE_FOR_FWPKG);
        }
    }
}

void DataConvertor::CopyBinInfo(BIN_INFO inputBinInfo, BIN_INFO &outPutBinInfo)
{
    outPutBinInfo.path = inputBinInfo.path;
    outPutBinInfo.type = inputBinInfo.type;
    outPutBinInfo.burnAddr = inputBinInfo.burnAddr;
    outPutBinInfo.burnSize = inputBinInfo.burnSize;
    outPutBinInfo.fileIndex = inputBinInfo.fileIndex;
    outPutBinInfo.fileSize = inputBinInfo.fileSize;
    outPutBinInfo.fileName = inputBinInfo.fileName;
}

bool DataConvertor::AddNotShowUiData(QMap<int, BIN_INFO> mapBinFileInfo,
    QMap<int, BIN_INFO> &actualMapBinFileInfo, bool &isNewFwpkgMode, QString importFilePath)
{
    BYTE* importData = nullptr;
    DWORD importLen = 0;
    if (Global::ReadFileData(importFilePath, importData, importLen) < 0) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetNotReadAgainTips().arg(importFilePath));
        return false;
    }
    auto *fwpkgHead = reinterpret_cast<FWPKG_HEAD *>(importData);
    auto *fwpkgHeadNew = reinterpret_cast<FWPKG_HEAD_NEW *>(importData);
    BIN_INFO_ARRAY infoArray;
    if (fwpkgHead->flag == 0xefbeaddf && fwpkgHead->imageNum < 0xffff) {
        isNewFwpkgMode = false;
        ParseFwpkgInfo(importFilePath, infoArray, fwpkgHead, false);
    } else {
        ParseNewFwpkgInfo(importFilePath, infoArray, fwpkgHeadNew, false);
    }
    for (int i = 0; i < infoArray.GetSize(); i++) {
        if (infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB ||
            infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB_SHA) {
            BIN_INFO binInfo;
            CopyBinInfo(infoArray.GetAt(i), binInfo);
            actualMapBinFileInfo.insert(actualMapBinFileInfo.size(), binInfo);
        }
    }
    for (int i = 0; i < mapBinFileInfo.size(); i++) {
        BIN_INFO binInfo;
        CopyBinInfo(mapBinFileInfo[i], binInfo);
        actualMapBinFileInfo.insert(actualMapBinFileInfo.size(), binInfo);
    }
    for (int i = 0; i < infoArray.GetSize(); i++) {
        if (infoArray.GetAt(i).type == IMAGE_TYPE::IMAGE_TYPE_DATABASE) {
            BIN_INFO binInfo;
            CopyBinInfo(infoArray.GetAt(i), binInfo);
            actualMapBinFileInfo.insert(actualMapBinFileInfo.size(), binInfo);
        }
    }
    if (importData != nullptr) {
        delete []importData;
        importData = nullptr;
    }
    return true;
}

bool DataConvertor::WritePartFileToFwpkg(QMap<int, BIN_INFO> actualMapBinFileInfo,
    bool isNewFwpkgMode, QFile &fwpkgNewFile, QDataStream &qDataStream)
{
    FWPKG_HEAD fwpkgHead;
    FWPKG_HEAD_NEW fwpkgHeadNew;

    int fileIndex = 0;
    int startCommonLen = sizeof(fwpkgHead.flag) + sizeof(fwpkgHead.crc) + sizeof(fwpkgHead.imageNum)
        + sizeof(fwpkgHead.totalFileSize);
    if (isNewFwpkgMode) {
        fileIndex = startCommonLen + sizeof(fwpkgHeadNew.name) + sizeof(IMAGE_INFO_NEW) * actualMapBinFileInfo.size();
    } else {
        fileIndex = startCommonLen + sizeof(IMAGE_INFO) * actualMapBinFileInfo.size();
    }

    fwpkgNewFile.seek(fileIndex);
    for (int i = 0; i < actualMapBinFileInfo.size(); i++) {
        QFile importFile(actualMapBinFileInfo[i].path);
        if (!importFile.open(QIODevice::ReadOnly)) {
            QMessageBox::warning(nullptr, "warning",
                stringClass.GetNotWriteAgainTips().arg(actualMapBinFileInfo[i].path));
            return false;
        }
        int fileSize = actualMapBinFileInfo[i].GetFileSize();
        if (importFile.seek(actualMapBinFileInfo[i].GetFileIndex())) {
            QByteArray data = importFile.read(fileSize);
            if (data.size() != fileSize) {
                importFile.close();
                QMessageBox::warning(nullptr, "warning",
                    stringClass.GetNotReadAgainTips().arg(actualMapBinFileInfo[i].path));
                return false;
            }
            if (fwpkgNewFile.write(data) == -1) {
                importFile.close();
                QMessageBox::warning(nullptr, "warning",
                    stringClass.GetWriteFileErrorTips().arg(fwpkgNewFile.fileName()));
                return false;
            }
        }
        importFile.close();
        QByteArray emptyStr(INTERVAL_EACH_FILE_FOR_FWPKG, 0);
        qDataStream.writeRawData(emptyStr.constData(), emptyStr.size());
    }
    return true;
}

bool DataConvertor::WriteImageHeadToFwpkg(QMap<int, BIN_INFO> actualMapBinFileInfo,
    bool isNewFwpkgMode, QFile &fwpkgNewFile, QDataStream &qDataStream)
{
    FWPKG_HEAD fwpkgHead;
    FWPKG_HEAD_NEW fwpkgHeadNew;

    int startCommonLen = sizeof(fwpkgHead.flag) + sizeof(fwpkgHead.crc) + sizeof(fwpkgHead.imageNum)
        + sizeof(fwpkgHead.totalFileSize);
    if (isNewFwpkgMode) {
        fwpkgNewFile.seek(startCommonLen + sizeof(fwpkgHeadNew.name));
    } else {
        fwpkgNewFile.seek(startCommonLen);
    }
    IMAGE_INFO imageInfo;
    IMAGE_INFO_NEW imageInfoNew;

    for (int i = 0; i < actualMapBinFileInfo.size(); i++) {
        QString fileName = actualMapBinFileInfo[i].fileName;
        if (fileName.isEmpty()) {
            QFile file(actualMapBinFileInfo[i].path);
            QFileInfo fileInfo(file);
            fileName = fileInfo.fileName();
            file.close();
        }
        QByteArray byteStr = fileName.toUtf8();
        qDataStream.writeRawData(byteStr.constData(), byteStr.size());
        if (isNewFwpkgMode) {
            QByteArray emptyStr(sizeof(imageInfoNew.name) - byteStr.size(), 0);
            qDataStream.writeRawData(emptyStr.constData(), emptyStr.size());
        } else {
            QByteArray emptyStr(sizeof(imageInfo.name) - byteStr.size(), 0);
            qDataStream.writeRawData(emptyStr.constData(), emptyStr.size());
        }

        qDataStream << actualMapBinFileInfo[i].GetFileIndex();
        qDataStream << actualMapBinFileInfo[i].GetFileSize();
        qDataStream << actualMapBinFileInfo[i].GetBurnAddr();
        qDataStream << actualMapBinFileInfo[i].GetBurnSize();
        qDataStream << static_cast<int>(actualMapBinFileInfo[i].type);
    }
    return true;
}

bool DataConvertor::WriteFwpkgHead(QMap<int, BIN_INFO> actualMapBinFileInfo,
    bool isNewFwpkgMode, QFile &fwpkgNewFile, QDataStream &qDataStream, QString saveFileName)
{
    FWPKG_HEAD fwpkgHead;
    // flag
    fwpkgNewFile.seek(0);
    if (isNewFwpkgMode) {
        qDataStream << 0xefbeaddc;
    } else {
        qDataStream << 0xefbeaddf;
    }
    // image num
    fwpkgNewFile.seek(sizeof(fwpkgHead.flag) + sizeof(fwpkgHead.crc));
    fwpkgHead.imageNum = actualMapBinFileInfo.size();
    qDataStream << fwpkgHead.imageNum;
    // file length
    fwpkgNewFile.seek(sizeof(fwpkgHead.flag) + sizeof(fwpkgHead.crc) + sizeof(fwpkgHead.imageNum));
    int fileLength = fwpkgNewFile.size();
    qDataStream << fileLength;
    // name
    if (isNewFwpkgMode) {
        fwpkgNewFile.seek(sizeof(fwpkgHead.flag) + sizeof(fwpkgHead.crc) + sizeof(fwpkgHead.imageNum)
            + sizeof(fwpkgHead.totalFileSize));
        QByteArray byteStr = FWPKG_HEAD_NEW_IMAGE_NAME.toUtf8();
        qDataStream.writeRawData(byteStr.constData(), byteStr.size());
    }
    // crc num
    fwpkgNewFile.seek(sizeof(fwpkgHead.flag));
    BYTE* data = nullptr;
    DWORD len = 0;
    if (Global::ReadFileData(saveFileName, data, len) < 0) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetNotReadAgainTips().arg(saveFileName));
        return false;
    }
    unsigned short crc = 0;
    if (isNewFwpkgMode) {
        auto *head = reinterpret_cast<FWPKG_HEAD_NEW *>(data);
        U32 crcDataLen = sizeof(FWPKG_HEAD_NEW) - sizeof(fwpkgHead.flag) - sizeof(fwpkgHead.crc)
            + sizeof(IMAGE_INFO_NEW) * head->imageNum;
        crc = ChannelClass::Channel::SopCrc16(reinterpret_cast<U8 *>(&head->imageNum), crcDataLen);
    } else {
        auto *head = reinterpret_cast<FWPKG_HEAD *>(data);
        U32 crcDataLen = sizeof(FWPKG_HEAD) - sizeof(fwpkgHead.flag) - sizeof(fwpkgHead.crc)
            + sizeof(IMAGE_INFO) * head->imageNum;
        crc = ChannelClass::Channel::SopCrc16(reinterpret_cast<U8 *>(&head->imageNum), crcDataLen);
    }
    qDataStream << crc;
    if (data != nullptr) {
        delete []data;
        data = nullptr;
    }
    return true;
}

bool DataConvertor::CreateNewFwpkgFile(QMap<int, BIN_INFO> mapBinFileInfo, QString saveFileName, QString importFilePath)
{
    QFile fwpkgNewFile(saveFileName);
    if (!fwpkgNewFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        QMessageBox::warning(nullptr, "warning", stringClass.GetNotWriteAgainTips().arg(saveFileName));
        return false;
    }

    QDataStream qDataStream(&fwpkgNewFile);
    qDataStream.setByteOrder(QDataStream::LittleEndian);

    bool isNewFwpkgMode = true;
    QMap<int, BIN_INFO> actualMapBinFileInfo;
    if (!AddNotShowUiData(mapBinFileInfo, actualMapBinFileInfo, isNewFwpkgMode, importFilePath)) {
        fwpkgNewFile.close();
        return false;
    }
    if (!WritePartFileToFwpkg(actualMapBinFileInfo, isNewFwpkgMode, fwpkgNewFile, qDataStream)) {
        fwpkgNewFile.close();
        return false;
    }

    SetFileIndex(actualMapBinFileInfo, isNewFwpkgMode);
    if (!WriteImageHeadToFwpkg(actualMapBinFileInfo, isNewFwpkgMode, fwpkgNewFile, qDataStream)) {
        fwpkgNewFile.close();
        return false;
    }

    if (!WriteFwpkgHead(actualMapBinFileInfo, isNewFwpkgMode, fwpkgNewFile, qDataStream, saveFileName)) {
        fwpkgNewFile.close();
        return false;
    }
    fwpkgNewFile.close();
    return true;
}

bool DataConvertor::SaveSpiltFwpkgFile(QMap<int, BIN_INFO> mapBinFileInfo, QString saveDirName, QString importFilePath)
{
    QMap<int, BIN_INFO> actualMapBinFileInfo;
    bool isNewFwpkgMode = true;
    if (!AddNotShowUiData(mapBinFileInfo, actualMapBinFileInfo, isNewFwpkgMode, importFilePath)) {
        return false;
    }
    for (int i = 0; i < actualMapBinFileInfo.size(); i++) {
        QString fileName = actualMapBinFileInfo[i].fileName;
        QString filePath = actualMapBinFileInfo[i].path;
        int fileIndex = actualMapBinFileInfo[i].GetFileIndex();
        int fileSize = actualMapBinFileInfo[i].GetFileSize();
        if (fileName.isEmpty()) {
            QFile file(filePath);
            QFileInfo fileInfo(file);
            fileName = fileInfo.fileName();
            file.close();
        }

        QFile importFile(filePath);
        if (!importFile.open(QIODevice::ReadOnly)) {
            QMessageBox::warning(nullptr, "warning", stringClass.GetNotWriteAgainTips().arg(filePath));
            return false;
        }
        QString saveFileName = saveDirName + "/" + fileName;
        QFile spiltFile(saveFileName);
        if (!spiltFile.open(QIODevice::WriteOnly)) {
            importFile.close();
            QMessageBox::warning(nullptr, "warning", stringClass.GetNotWriteAgainTips().arg(saveFileName));
            return false;
        }

        bool result = false;
        if (importFile.seek(fileIndex)) {
            QByteArray data = importFile.read(fileSize);
            if (data.size() == fileSize && spiltFile.write(data) != -1) {
                result = true;
            }
        }
        importFile.close();
        spiltFile.close();
        if (!result) {
            QMessageBox::warning(nullptr, "warning", stringClass.GetWriteFileErrorTips().arg(saveFileName));
            return false;
        }
    }
    return true;
};
